﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ComponentModel;

namespace WebPALTT.Lib
{
    /// <summary>
    /// A Loop Action which loops through a folder of actions for a given count.
    /// </summary>
    [Serializable]
    public class ActionItem_Loop : ActionItem
    {
        /// <summary>
        /// Static method containing the CustomType of this action for comparison.
        /// </summary>
        public static string Type { get { return "Loop"; } }
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public override ActionType ActionType { get { return ActionType.Action; } }
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public override string CustomType { get { return ActionItem_Loop.Type; } }
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public override System.Drawing.Image Icon { get { return global::WebPALTT.Lib.Icons.arrow_refresh; } }

        public override bool HasChildren { get { return true; } }        
        public override bool CanAddChildren { get { return false; } }
        public override string[] DataHeaders { get { return new string[] { "Count", "Enter Loop" }; } }
        public override string[] DataHeaders_Save { get { return new string[] { "Count", "Enter Loop" }; } }

        public override ExecutionStatus ExecutionStatus { get { return base.mExecutionStatus; } }

        int mMaxCount;
        int mLoopCount;
        ActionItemCollection mActions;

        /// <summary>
        /// Gets or sets the number of times this action will loop through its list of actions.
        /// </summary>
        [DescriptionAttribute("Number of times to loop.")]
        public int Count { get { return mMaxCount; } set { mMaxCount = value; } }
        /// <summary>
        /// Gets or sets the number of times this action as already run. 
        /// The loop continues while LoopCount &lt Count
        /// </summary>
        [BrowsableAttribute(false)]
        public int LoopCount { get { return mLoopCount; } set { mLoopCount = value; } }

        /// <summary>
        /// Gets or sets the action item collection to loop through. 
        /// This returns the collection inside the folder (rather than the folder action returned by the Children property).
        /// </summary>
        [BrowsableAttribute(false)]
        public ActionItemCollection Actions { get { return mActions[0].Children; } }

        public ActionItem_Loop() : this("") { }

        public ActionItem_Loop(string name) : this(name, 0, null) { }

        public ActionItem_Loop(string name, int maxCount, ActionItemCollection actions)
            : base(name)
        {
            mMaxCount = maxCount;
            mLoopCount = 0;
            mActions = new ActionItemCollection();
            mActions.Add(new ActionItem_Folder("Actions", actions));
            mActions.IsReadOnly = true;
        }

        public ActionItem_Loop(SerializationInfo info, StreamingContext ctxt)
            : base(info, ctxt)
        {
            mMaxCount = (int)info.GetValue("LoopCount", typeof(int));
            mActions = new ActionItemCollection();
            ActionItem_Folder actions;
            try
            {
                actions = (ActionItem_Folder)info.GetValue("Actions_Folder", typeof(ActionItem_Folder));
            }
            catch (SerializationException)
            {
                actions = new ActionItem_Folder("Actions", (ActionItemCollection)info.GetValue("Actions", typeof(ActionItemCollection)));
            }            
            mActions.Add(actions);
            mActions.IsReadOnly = true;
            mLoopCount = 0;
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            base.GetObjectData(info, ctxt);
            info.AddValue("LoopCount", mMaxCount);
            info.AddValue("Actions_Folder", (ActionItem_Folder)mActions[0]);
        }

        public override string[] Validate()
        {
            List<string> errors = new List<string> { };
            if (Name.Equals("Then") || Name.Equals("Else") || Name.Equals("Actions"))
                errors.Add("Error: action[" + Name + "(" + ActionType + ")] is using a reserverd name.");

            if (Actions.Count == 0)
                errors.Add("Warning: action[" + Name + "(" + ActionType + ")]. - Loop action doesn't contain any sub actions");
            errors.AddRange(mActions[0].Validate());

            return errors.ToArray();
        }

        public override void SetParent(ActionItem parent, int index = 0)
        {
            base.SetParent(parent, index);
            mActions[0].SetParent(this, 0);
        }

        public override ActionItem FindChild(Guid key)
        {
            return mActions.Find(
                delegate(ActionItem item)
                {
                    if (Guid.Equals(item.Key, key))
                        return true;
                    return false;
                }, true);
        }

        public override ActionItem[] FindChildren(Guid key)
        {
            List<ActionItem> list = new List<ActionItem> { };
            list.AddRange(mActions.FindAll(
                delegate(ActionItem item)
                {
                    if (Guid.Equals(item.Key, key))
                        return true;
                    return false;
                }, true));
            return list.ToArray();
        }

        public override ActionItemCollection Children
        {
            get { 
                return mActions; 
            }
        }

        public override Dictionary<string, object> Execute(Scenario scenario, ScenarioResults resultScene, Type scriptType, object scriptObj)
        {
            Dictionary<string, object> results = new Dictionary<string, object>();
            results.Add("Count", this.LoopCount);
            results.Add("Enter Loop", this.LoopCount < this.Count);
            if (this.LoopCount < this.Count)
                base.mExecutionStatus = Lib.ExecutionStatus.RunChildren;
            else
            {
                base.mExecutionStatus = Lib.ExecutionStatus.Complete;
                this.LoopCount++;
                return null;
            }
            this.LoopCount++;
            return results;
        }
    }
}
